﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Linq;
using P2PChat.Security.Cryptography;

namespace P2PChat.Net
{
    public class PacketParser
    {
        public PacketType UnpackContent(byte[] packet, out object result)
        {
            return UnpackContent(packet, out result, null);
        }

        public PacketType UnpackContent(byte[] packet, out object result, IEncryptography iEncryptography)
        {
            if (packet == null) { result = null; return PacketType.NullPack; }
            if (packet.Length <= 1)
            {
                result = null;
                return PacketType.IgnorePack;
            }

            byte header = packet[0];
            byte[] content;
            switch (header)
            {
                case 0x01: // 字符串
                    content = new byte[packet.Length - 1];
                    packet.CopyTo(content, 1);
                    result = Encoding.UTF8.GetString(content);
                    return PacketType.RawString;

                case 0x02: // XML字符串
                    content = new byte[packet.Length - 1];
                    packet.CopyTo(content, 1);
                    XElement xmlStr = XElement.Parse(Encoding.UTF8.GetString(content), LoadOptions.PreserveWhitespace);
                    result = xmlStr;
                    return PacketType.RawXmlString;

                case 0x03: // 公钥传输
                    content = new byte[packet.Length - 1];
                    packet.CopyTo(content, 1);
                    result = Encoding.UTF8.GetString(content);
                    return PacketType.PublicKey;

                case 0x10: // 加密字符串
                    content = new byte[packet.Length - 1];
                    packet.CopyTo(content, 1);

                    try
                    {
                        if (iEncryptography == null)
                        {
                            result = content;
                            return PacketType.CryptedString;
                        }
                        else
                        {
                            result = iEncryptography.Decrypt(content);
                            return PacketType.RawString;
                        }
                    }
                    catch
                    {
                        result = content;
                        return PacketType.CryptedString;
                    }


                case 0x11: // 加密的XML字符串
                    content = new byte[packet.Length - 1];
                    packet.CopyTo(content, 1);
                    try
                    {
                        if (iEncryptography == null)
                        {
                            result = content;
                            return PacketType.CryptedXmlString;
                        }
                        else
                        {
                            result = iEncryptography.Decrypt(content);
                            return PacketType.RawXmlString;
                        }
                    }
                    catch
                    {
                        result = content;
                        return PacketType.CryptedXmlString;
                    }

                default:
                    result = null;
                    return PacketType.IgnorePack;
            }
        }

        public byte[] PackContent(PacketType type, object content)
        {
            switch (type)
            {
                case PacketType.RawString:
                    return new byte[] { 0x01 }.Concat(Encoding.UTF8.GetBytes(content as string)).ToArray();

                case PacketType.RawXmlString:
                    return new byte[] { 0x02 }.Concat(Encoding.UTF8.GetBytes(content as string)).ToArray();

                case PacketType.PublicKey:
                    return new byte[] { 0x03 }.Concat(Encoding.UTF8.GetBytes(content as string)).ToArray();

                case PacketType.CryptedString:
                    return new byte[] { 0x11 }.Concat((byte[])content).ToArray();

                case PacketType.CryptedXmlString:
                    return new byte[] { 0x12 }.Concat((byte[])content).ToArray();
            }

            return null;
        }

    }
}
